package com.example.day43_opengl_filter2;

import android.content.Context;
import android.opengl.GLES20;

/**
 * Description:Fbo离屏渲染
 * Created by Gdu on 2021/5/7 1:38.
 */

public class AbstractFboFilter extends AbstractFilter {
    int[] frameBuffer; //fbo数组
    int[] frameTextures; //纹理

    public AbstractFboFilter(Context context, int vertexShaderId, int fragmentShaderId) {
        super(context, vertexShaderId, fragmentShaderId);
    }

    /**
     * fbo初始化
     * @param width
     * @param height
     */
    @Override
    public void setSize(int width, int height) {
        super.setSize(width,height);
        releaseFrame();
        //实例化fbo,让摄像头的数据先渲染到fbo
        frameBuffer = new int[1];
        GLES20.glGenFramebuffers(1,frameBuffer,0);
        //生成一个纹理(纹理可以理解成图层)
        frameTextures = new int[1]; //接收GPU返回的纹理坐标
        GLES20.glGenTextures(frameTextures.length, frameTextures,0);
        //配置纹理
        for (int i = 0; i < frameTextures.length; i++) {
            //绑定纹理 开始操作纹理 ,相当于开启原子性的事务
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextures[i]);
            //给图层配置显示方式 放大模糊(GL_LINEAR)或放大锯齿(GL_NEAREST) 放大过滤
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,
                    GLES20.GL_NEAREST);
            //给图层配置显示方式 缩小模糊(GL_LINEAR)或缩小锯齿(GL_NEAREST) 缩小过滤
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,
                    GLES20.GL_LINEAR);

            //结束绑定纹理 告诉GPU操作完了
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
        }
        //设置纹理显示颜色
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextures[0]);
        /**
         * 指定一个二维的纹理图片
         * level
         *     指定细节级别，0级表示基本图像，n级则表示Mipmap缩小n级之后的图像（缩小2^n）
         * internalformat
         *     指定纹理内部格式，必须是下列符号常量之一：GL_ALPHA，GL_LUMINANCE，GL_LUMINANCE_ALPHA，GL_RGB，GL_RGBA。
         * width height
         *     指定纹理图像的宽高，所有实现都支持宽高至少为64 纹素的2D纹理图像和宽高至少为16 纹素的立方体贴图纹理图像 。
         * border
         *     指定边框的宽度。必须为0。
         * format
         *     指定纹理数据的格式。必须匹配internalformat。下面的符号值被接受：GL_ALPHA，GL_RGB，GL_RGBA，GL_LUMINANCE，和GL_LUMINANCE_ALPHA。
         * type
         *     指定纹理数据的数据类型。下面的符号值被接受：GL_UNSIGNED_BYTE，GL_UNSIGNED_SHORT_5_6_5，GL_UNSIGNED_SHORT_4_4_4_4，和GL_UNSIGNED_SHORT_5_5_5_1。
         * data
         *     指定一个指向内存中图像数据的指针。
         */
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,width,height,0,
                GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,null);
        //开始操作buffer
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,frameBuffer[0]);
        //真正绑定fbo和纹理
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
                GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
                frameTextures[0],
                0);
        //释放纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
        //释放buffer
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
    }

    @Override
    public int onDraw(int textures) {
        //将数据渲染到fbo中
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,frameBuffer[0]);
        super.onDraw(textures);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
        //数据不在textures中,已经保存到fbo中,所以返回frameBuffer[0]
        return frameBuffer[0];
    }

    private void releaseFrame() {
        if (frameTextures != null) {
            GLES20.glDeleteTextures(1, frameTextures, 0);
            frameTextures = null;
        }

        if (frameBuffer != null) {
            GLES20.glDeleteFramebuffers(1, frameBuffer, 0);
        }
    }

}
